package main

import (
	"fmt"
	"math"
	"time"
)

type PIDController struct {
	Setpoint         float64
	Kp, Ki, Kd       float64
	ProportionalTerm float64
	IntegralTerm     float64
	DerivativeTerm   float64
	LastError        float64 // 存储上一次的错误值
	LastTime         int64   // 存储上一次调用Compute方法的时间戳
	OutputMin        float64 // 输出最小值
	OutputMax        float64 // 输出最大值
}

func NewPIDController(setpoint, kp, ki, kd, outputMin, outputMax float64) *PIDController {
	return &PIDController{
		Setpoint:         setpoint,
		Kp:               kp,
		Ki:               ki,
		Kd:               kd,
		OutputMin:        outputMin,
		OutputMax:        outputMax,
		LastTime:         time.Now().UnixNano() / int64(time.Millisecond), // 初始化时设置当前时间戳
	}
}

func (pid *PIDController) Compute(currentValue float64) float64 {
	error := pid.Setpoint - currentValue
	currentTime := time.Now().UnixNano() / int64(time.Millisecond)
	elapsedTime := float64(currentTime-pid.LastTime) / 1000.0 // 修正时间差计算，并转换为秒

	if elapsedTime <= 0 {
		elapsedTime = 0.01 // 避免除以零
	}

	pid.ProportionalTerm = pid.Kp * error
	pid.IntegralTerm += pid.Ki * error * elapsedTime
	pid.DerivativeTerm = pid.Kd * (error - pid.LastError) / elapsedTime

	// 限制输出范围
	output := pid.ProportionalTerm + pid.IntegralTerm + pid.DerivativeTerm
	output = math.Max(output, pid.OutputMin)
	output = math.Min(output, pid.OutputMax)

	pid.LastError = error
	pid.LastTime = currentTime // 更新时间戳

	return output
}

func main() {
	setpoint := 20.0 // 目标回风温度
	kp := 0.4        // 制冷比例带
	ki := 0.2        // 制冷积分常数
	kd := 0.5        // 制冷微分常数
	outputMin := 0.01  // 输出最小值
	outputMax := 10.0 // 输出最大值

	// 创建 PID 控制器
	pid := NewPIDController(setpoint, kp, ki, kd, outputMin, outputMax)

	// 模拟回风温度变化
	currentValue := 25.0 // 当前回风温度

	for i := 0; i < 10; i++ {
		// 计算 PID 控制输出
		output := pid.Compute(currentValue)

		// 模拟控制器作用后回风温度的变化
		currentValue -= output

		fmt.Printf("Iteration %d - Output: %.2f, Current Value: %.2f\n", i+1, output, currentValue)

		time.Sleep(1 * time.Second)
	}
}
